package com.cheer.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.math.MathUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.cell.CellUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cheer.common.Page;
import com.cheer.dao.OaLearnEntryDao;
import com.cheer.dto.OaLearnEntryQueryDTO;
import com.cheer.dto.OaLearnNumberDTO;
import com.cheer.entity.*;
import com.cheer.enums.OaLearnClassTypeEnum;
import com.cheer.enums.OaRateEnum;
import com.cheer.exception.GlobalExceptionHandler;
import com.cheer.exception.ServiceException;
import com.cheer.service.*;
import com.cheer.utils.ExcelsUtil;
import com.cheer.vo.*;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service("oaLearnEntryService")
public class OaLearnEntryServiceImpl extends ServiceImpl<OaLearnEntryDao, OaLearnEntryEntity> implements OaLearnEntryService {

    @Autowired
    private OaLearnEntryDao oaLearnEntryDao;

    @Autowired
    private OaUserService oaUserService;

    @Autowired
    private OaLearnClassService oaLearnClassService;

    @Autowired
    private OaLearnService oaLearnService;

    @Autowired
    private OaLeamPeriodsService oaLeamPeriodsService;

    @Autowired
    private HttpServletResponse response;

    @Override
    public List<OaHistoryListVO> listByUserId(Integer userId) {
        String openid = oaUserService.getOpenidById(userId);
        if (openid == null) {
            throw new ServiceException("用户不存在");
        }

        List<OaLearnEntryEntity> entryList = oaLearnEntryDao.selectListByOpenid(openid);

        Set<String> idSet = new HashSet<>();
        entryList.forEach(entry -> {
            String[] split = StringUtils.split(entry.getPath(), ",");
            idSet.addAll(Lists.newArrayList(split));
        });
        idSet.remove("0");

        Map<Integer, String> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(idSet)) {
            oaLearnClassService.listByIds(idSet)
                    .forEach(learnClass -> map.put(learnClass.getId(), learnClass.getName()));
        }

        Set<Integer> learnIdSet = entryList.stream()
                .map(OaLearnEntryEntity::getLearnId)
                .collect(Collectors.toSet());

        Map<Integer, String> nameMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(learnIdSet)) {
            oaLearnService.listByIds(learnIdSet)
                    .forEach(learn -> nameMap.put(learn.getId(), learn.getName()));
        }

        return entryList.stream()
                .map(entry -> {
                    OaHistoryListVO historyListVO = new OaHistoryListVO()
                            .setAddTime(DateUtil.format(DateUtil.date(Long.valueOf(entry.getAddTime()) * 1000),
                                    DatePattern.NORM_DATETIME_PATTERN))
                            .setLearnName(nameMap.get(entry.getLearnId()));

                    String[] split = StringUtils.split(entry.getPath(), ",");
                    if (ArrayUtils.isNotEmpty(split)) {
                        List<String> learnClass = new ArrayList<>();
                        for (String str : split) {
                            if (map.get(Integer.valueOf(str)) != null) {
                                learnClass.add(map.get(Integer.valueOf(str)));
                            } else {
                                break;
                            }
                        }
                        if (CollectionUtils.isNotEmpty(learnClass)) {
                            historyListVO.setLearnClass(StringUtils.join(learnClass, "-"));
                        }
                    }

                    return historyListVO;
                })
                .collect(Collectors.toList());

    }

    @Override
    public Page<OaLearnEntryVO> list(Integer pageNum, Integer pageSize, Integer learnId, Integer pid) {
        IPage<OaLearnClassEntity> page = oaLearnClassService.listByPid(pageNum, pageSize, pid);

        Set<String> idSet = new HashSet<>();
        page.getRecords()
                .forEach(learnClass -> {
                    String[] split = StringUtils.split(learnClass.getPath(), ",");
                    idSet.addAll(Lists.newArrayList(split));
                });
        idSet.remove("0");

        Map<Integer, String> map = new HashMap<>();

        if (CollectionUtils.isNotEmpty(idSet)) {
            List<Integer> ids = idSet.stream()
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
            oaLearnClassService.listByIds(ids)
                    .forEach(learnClass -> map.put(learnClass.getId(), learnClass.getName()));
        }

        List<OaLearnEntryVO> list = page.getRecords().stream()
                .map(learnClass -> {
                    OaLearnEntryVO oaLearnEntryVO = new OaLearnEntryVO()
                            .setId(learnClass.getId());

                    String[] split = StringUtils.split(learnClass.getPath(), ",");

                    List<String> pLearnClass = new ArrayList<>();
                    for (String str : split) {
                        if (!str.equals("0")) {
                            String pClass = map.get(Integer.valueOf(str));
                            if (pClass != null) {
                                pLearnClass.add(pClass);
                            }
                        }
                    }
                    pLearnClass.add(learnClass.getName());
                    oaLearnEntryVO.setName(StringUtils.join(pLearnClass, "-"));

                    oaLearnEntryVO.setNumber(oaLearnEntryDao.selectLearnNumberByPath(learnId,
                            learnClass.getPath() + learnClass.getId() + ","));

                    return oaLearnEntryVO;
                })
                .collect(Collectors.toList());

        return new Page<>(page, list);
    }

    @Override
    public Page<OaLearnEntryDetailVO> detail(Integer pageNum, Integer pageSize, Integer learnId, Integer pid) {
        OaLearnClassEntity learnClass = oaLearnClassService.getById(pid);
        if (learnClass == null) {
            throw new ServiceException("单位不存在");
        }

        IPage<OaLearnEntryEntity> page = oaLearnEntryDao.selectPageByPath(pageNum, pageSize, learnId,
                learnClass.getPath() + learnClass.getId() + ",");

        List<String> openids = page.getRecords().stream()
                .map(OaLearnEntryEntity::getOpenid)
                .collect(Collectors.toList());

        Map<String, OaUserEntity> userMap = CollectionUtils.isEmpty(openids) ? new HashMap<>() :
                oaUserService.listByOpenids(openids).stream()
                        .collect(Collectors.toMap(OaUserEntity::getOpenid, Function.identity()));

        Set<String> idSet = new HashSet<>();
        page.getRecords()
                .forEach(learnEntry -> {
                    String[] split = StringUtils.split(learnEntry.getPath(), ",");
                    idSet.addAll(Lists.newArrayList(split));
                });
        idSet.remove("0");

        Map<Integer, String> map = new HashMap<>();

        if (CollectionUtils.isNotEmpty(idSet)) {
            List<Integer> ids = idSet.stream()
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
            oaLearnClassService.listByIds(ids)
                    .forEach(oaLearnClassEntity -> map.put(oaLearnClassEntity.getId(), oaLearnClassEntity.getName()));
        }

        List<OaLearnEntryDetailVO> list = page.getRecords().stream()
                .map(oaLearnEntryEntity -> {
                    OaLearnEntryDetailVO learnEntryDetailVO = new OaLearnEntryDetailVO()
                            .setName(oaLearnEntryEntity.getName())
                            .setAddTime(DateUtil.format(DateUtil.date(Long.valueOf(oaLearnEntryEntity.getAddTime()) * 1000),
                                    DatePattern.NORM_DATETIME_PATTERN));

                    OaUserEntity user = userMap.get(oaLearnEntryEntity.getOpenid());
                    if (user != null) {
                        learnEntryDetailVO.setSex(user.getSex())
                                .setType(user.getType())
                                .setPoliticsStatus(user.getPoliticsStatus());
                    }

                    String[] split = StringUtils.split(oaLearnEntryEntity.getPath(), ",");

                    List<String> pLearnClass = new ArrayList<>();
                    for (String str : split) {
                        if (!str.equals("0")) {
                            String pClass = map.get(Integer.valueOf(str));
                            if (pClass != null) {
                                pLearnClass.add(pClass);
                            }
                        }
                    }

                    learnEntryDetailVO.setLearnClass(StringUtils.join(pLearnClass, "-"));

                    return learnEntryDetailVO;
                })
                .collect(Collectors.toList());

        return new Page<>(page, list);
    }

    @Override
    public OaLearnEntryCompareVO compare(OaLearnEntryQueryDTO learnEntryQueryDTO) {

        List<OaLearnClassEntity> learnClassEntityList = oaLearnClassService.listByIdAndPid(learnEntryQueryDTO.getPid());
        OaLearnEntryCompareVO learnEntryCompareVO = compare(learnEntryQueryDTO, learnClassEntityList);

        return learnEntryCompareVO;
    }


    private OaLearnEntryCompareVO compare(OaLearnEntryQueryDTO learnEntryQueryDTO, List<OaLearnClassEntity> learnClassEntityList) {

        OaLearnEntity learn = oaLearnService.getById(learnEntryQueryDTO.getLearnId());
        if (learn == null) {
            throw new ServiceException("所选期不存在");
        }

        OaLeamPeriodsEntity leamPeriods = oaLeamPeriodsService.getById(learn.getPid());
        if (leamPeriods == null) {
            throw new ServiceException("所选季不存在");
        }

        Map<Integer, OaLearnEntity> compareMap = CollectionUtils.isEmpty(learnEntryQueryDTO.getCompareIds()) ?
                new HashMap<>() : oaLearnService.listByIds(learnEntryQueryDTO.getCompareIds()).stream()
                .collect(Collectors.toMap(OaLearnEntity::getId, Function.identity()));

        // 查询期数
        OaLearnEntryCompareVO learnEntryCompareVO = new OaLearnEntryCompareVO()
                .setChoose(leamPeriods.getName() + learn.getName());

        List<String> compare = new ArrayList<>();
        List<Integer> compareIds = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(learnEntryQueryDTO.getCompareIds())) {
            for (Integer compareId : learnEntryQueryDTO.getCompareIds()) {
                OaLearnEntity learnItem = compareMap.get(compareId);
                if (learnItem != null) {
                    compareIds.add(compareId);
                    compare.add(learnItem.getName());
                }
            }
        }

        learnEntryCompareVO.setCompare(compare);

        Set<String> idSet = new HashSet<>();
        learnClassEntityList
                .forEach(learnClass -> {
                    String[] split = StringUtils.split(learnClass.getPath(), ",");
                    idSet.addAll(Lists.newArrayList(split));
                });
        idSet.remove("0");

        Map<Integer, String> map = new HashMap<>();

        if (CollectionUtils.isNotEmpty(idSet)) {
            List<Integer> ids = idSet.stream().map(Integer::valueOf).collect(Collectors.toList());
            oaLearnClassService.listByIds(ids).forEach(learnClass -> map.put(learnClass.getId(), learnClass.getName()));
        }

        compareIds.add(0, learnEntryQueryDTO.getLearnId());

        List<OaLearnEntryCompareInfoVO> list = learnClassEntityList.stream()
                .map(learnClass -> {
                    OaLearnEntryCompareInfoVO learnEntryCompareInfoVO = new OaLearnEntryCompareInfoVO()
                            .setId(learnClass.getId());

                    String[] split = StringUtils.split(learnClass.getPath(), ",");

                    List<String> pLearnClass = new ArrayList<>();
                    for (String str : split) {
                        if (!str.equals("0")) {
                            String pClass = map.get(Integer.valueOf(str));
                            if (pClass != null) {
                                pLearnClass.add(pClass);
                            }
                        }
                    }
                    pLearnClass.add(learnClass.getName());
                    learnEntryCompareInfoVO.setName(StringUtils.join(pLearnClass, "-"));

                    List<OaLearnNumberDTO> learnNumberDTOS = oaLearnEntryDao.selectLearnNumberByPathGroup(compareIds,
                            learnClass.getPath() + learnClass.getId() + ",");
                    Map<Integer, Integer> numberMap = learnNumberDTOS.stream()
                            .collect(Collectors.toMap(OaLearnNumberDTO::getId, OaLearnNumberDTO::getNumber));

                    Integer total = learnClass.getNum();
                    double rate = (double) 0;

                    NumberFormat nt = NumberFormat.getPercentInstance();
                    nt.setMinimumFractionDigits(2);

                    List<OaLearnEntryCompareItemVO> itemVOList = new ArrayList<>();
                    for (int i = 0; i < compareIds.size(); i++) {

                        Integer number = numberMap.get(compareIds.get(i));
                        if (i == 0) {
                            if (total > 0 && number != null) {
                                double r = number * 1.0 / total;
                                rate = Math.round(r * 10000) / 10000.0;
                            }
                            learnEntryCompareInfoVO.setRate(rate);
                            learnEntryCompareInfoVO.setRatio(nt.format(rate));
                            learnEntryCompareInfoVO.setCount(number == null ? 0 : number);
                        } else {
                            double r = (double) 0;
                            if (total > 0 && number != null) {
                                r = number * 1.0 / total;
                                r = Math.round(r * 10000) / 10000.0;
                            }

                            OaLearnEntryCompareItemVO compareItemVO = new OaLearnEntryCompareItemVO()
                                    .setRatio(nt.format(r));
                            if (r > rate) {
                                compareItemVO.setRate(OaRateEnum.UP.getCode());
                            } else if (r == rate) {
                                compareItemVO.setRate(OaRateEnum.NONE.getCode());
                            } else {
                                compareItemVO.setRate(OaRateEnum.DOWN.getCode());
                            }

                            itemVOList.add(compareItemVO);
                        }
                    }

                    learnEntryCompareInfoVO.setList(itemVOList);

                    return learnEntryCompareInfoVO;
                })
                .sorted((o1, o2) -> {
                    if (Objects.equals(o1.getId(), learnEntryQueryDTO.getPid())) {
                        return -1;
                    } else if (Objects.equals(o2.getId(), learnEntryQueryDTO.getPid())) {
                        return 1;
                    }
                    if (o1.getRate() - o2.getRate() < 0) {
                        return 1;
                    } else if (o1.getRate() - o2.getRate() > 0) {
                        return -1;
                    } else {
                        return 0;
                    }
                })
                .collect(Collectors.toList());

        learnEntryCompareVO.setPage(list);
        return learnEntryCompareVO;
    }

    @Override
    public Integer countByLearnId(Integer learnId) {
        return oaLearnEntryDao.selectCountByLearnId(learnId);
    }

    @Override
    public List<OaLearnEntryVO> listHome(Integer pid) {
        OaLearnEntity learn = oaLearnService.getFirst();
        if (learn == null) {
            return new ArrayList<>();
        }

        List<OaLearnClassEntity> learnClassList = oaLearnClassService.listByPid(pid);

        Set<String> idSet = new HashSet<>();
        learnClassList.forEach(learnClass -> {
            String[] split = StringUtils.split(learnClass.getPath(), ",");
            idSet.addAll(Lists.newArrayList(split));
        });
        idSet.remove("0");

        Map<Integer, String> map = new HashMap<>();

        if (CollectionUtils.isNotEmpty(idSet)) {
            List<Integer> ids = idSet.stream()
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
            oaLearnClassService.listByIds(ids)
                    .forEach(learnClass -> map.put(learnClass.getId(), learnClass.getName()));
        }

        return learnClassList.parallelStream()
                .map(learnClass -> {
                    OaLearnEntryVO oaLearnEntryVO = new OaLearnEntryVO()
                            .setId(learnClass.getId());

                    String[] split = StringUtils.split(learnClass.getPath(), ",");

                    List<String> pLearnClass = new ArrayList<>();
                    for (String str : split) {
                        if (!str.equals("0")) {
                            String pClass = map.get(Integer.valueOf(str));
                            if (pClass != null) {
                                pLearnClass.add(pClass);
                            }
                        }
                    }
                    pLearnClass.add(learnClass.getName());
                    oaLearnEntryVO.setName(StringUtils.join(pLearnClass, "-"));

                    oaLearnEntryVO.setNumber(oaLearnEntryDao.selectLearnNumberByPath(learn.getId(),
                            learnClass.getPath() + learnClass.getId() + ","));

                    return oaLearnEntryVO;
                })
                .sorted(Comparator.comparingInt(OaLearnEntryVO::getNumber))
                .collect(Collectors.toList());
    }

    @Override
    public void download(Integer learnId, Integer pid, HttpServletResponse response) {
        List<OaLearnClassEntity> learnClassEntities = oaLearnClassService.listByIdAndPid(pid);

        Set<String> idSet = new HashSet<>();
        learnClassEntities.forEach(learnClass -> {
            String[] split = StringUtils.split(learnClass.getPath(), ",");
            idSet.addAll(Lists.newArrayList(split));
        });
        idSet.remove("0");

        Map<Integer, String> map = new HashMap<>();

        if (CollectionUtils.isNotEmpty(idSet)) {
            List<Integer> ids = idSet.stream()
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
            oaLearnClassService.listByIds(ids)
                    .forEach(learnClass -> map.put(learnClass.getId(), learnClass.getName()));
        }

        List<OaLearnEntryVO> list = learnClassEntities.stream()
                .map(learnClass -> {
                    OaLearnEntryVO oaLearnEntryVO = new OaLearnEntryVO()
                            .setId(learnClass.getId());

                    String[] split = StringUtils.split(learnClass.getPath(), ",");

                    List<String> pLearnClass = new ArrayList<>();
                    for (String str : split) {
                        if (!str.equals("0")) {
                            String pClass = map.get(Integer.valueOf(str));
                            if (pClass != null) {
                                pLearnClass.add(pClass);
                            }
                        }
                    }
                    pLearnClass.add(learnClass.getName());
                    oaLearnEntryVO.setName(StringUtils.join(pLearnClass, "-"));

                    oaLearnEntryVO.setNumber(oaLearnEntryDao.selectLearnNumberByPath(learnId,
                            learnClass.getPath() + learnClass.getId() + ","));

                    return oaLearnEntryVO;
                })
                .collect(Collectors.toList());

        List<Map<String, Object>> excelList = new ArrayList<>();
        Map<String, Object> header = new HashMap<>();
        header.put("sheetName", "报名表");
        excelList.add(header);

        for (OaLearnEntryVO learnEntryVO : list) {
            Map<String, Object> line = new HashMap<>();
            line.put("learnClass", learnEntryVO.getName());
            line.put("number", learnEntryVO.getNumber());
            excelList.add(line);
        }

        String[] columnNames = {"单位名称", "人数"};
        String[] keys = {"learnClass", "number"};

        response.setContentType("application/x-download");
        response.addHeader("Content-Disposition", "attachment;filename=报名表.xlsx;filename*=UTF-8''"
                + URLUtil.encode("报名表.xlsx"));
        try (SXSSFWorkbook xssfWorkbook = ExcelsUtil.ExcelSingleOutputStream(excelList, keys, columnNames)) {
            xssfWorkbook.write(response.getOutputStream());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException("下载异常");
        }
    }

    @Override
    public void add(String openid, Integer learnId, Date date) {
        OaLearnEntity learn = oaLearnService.getById(learnId);

        //TODO 当前时间和课程的开始时间和结束时间比较；这里需要注意!!!!!
        if (date.getTime() / 1000 < Integer.valueOf(learn.getStartTime()) ||
                date.getTime() / 1000 > Integer.valueOf(learn.getEndTime())) {
            return;
        }

        if (oaLearnEntryDao.selectOneByOpenid(openid, learnId) != null) {
            return;
        }

        OaUserEntity user = oaUserService.getByOpenid(openid);
        if (user == null) {
            return;
        }

        OaLearnEntryEntity learnEntryEntity = new OaLearnEntryEntity()
                .setName(user.getName())
                .setDepartment(Integer.valueOf(user.getDepartment()))
                .setPath(user.getPath())
                .setLearnClass(Integer.valueOf(learn.getPid()))
                .setLearnId(learnId)
                .setOpenid(openid)
                .setAddTime(String.valueOf(date.getTime() / 1000));

        oaLearnEntryDao.insert(learnEntryEntity);
    }

    @Override
    public void updatePathByDepartment(Integer department, String path) {
        oaLearnEntryDao.updatePathByDepartment(department, path);
    }

    @Override
    public void updateByOpenid(OaLearnEntryEntity oaLearnEntryEntity) {
        oaLearnEntryDao.updateByOpenid(oaLearnEntryEntity);
    }

    @Override
    public void detailDownload(Integer learnId, Integer pid, HttpServletResponse response) {
        OaLearnClassEntity learnClass = oaLearnClassService.getById(pid);
        if (learnClass == null) {
            throw new ServiceException("单位不存在");
        }

        List<OaLearnEntryEntity> learnEntryEntityList = oaLearnEntryDao.selectListByPath(learnId, learnClass.getPath() + learnClass.getId() + ",");

        List<String> openids = learnEntryEntityList.stream()
                .map(OaLearnEntryEntity::getOpenid)
                .collect(Collectors.toList());

        Map<String, OaUserEntity> userMap = CollectionUtils.isEmpty(openids) ? new HashMap<>() :
                oaUserService.listByOpenids(openids).stream()
                        .collect(Collectors.toMap(OaUserEntity::getOpenid, Function.identity()));

        Set<String> idSet = new HashSet<>();
        learnEntryEntityList
                .forEach(learnEntry -> {
                    String[] split = StringUtils.split(learnEntry.getPath(), ",");
                    idSet.addAll(Lists.newArrayList(split));
                });
        idSet.remove("0");

        Map<Integer, String> map = new HashMap<>();

        if (CollectionUtils.isNotEmpty(idSet)) {
            List<Integer> ids = idSet.stream()
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
            oaLearnClassService.listByIds(ids)
                    .forEach(oaLearnClassEntity -> map.put(oaLearnClassEntity.getId(), oaLearnClassEntity.getName()));
        }

        List<OaLearnEntryDetailVO> list = learnEntryEntityList.stream()
                .map(oaLearnEntryEntity -> {
                    OaLearnEntryDetailVO learnEntryDetailVO = new OaLearnEntryDetailVO()
                            .setName(oaLearnEntryEntity.getName())
                            .setAddTime(DateUtil.format(DateUtil.date(Long.valueOf(oaLearnEntryEntity.getAddTime()) * 1000),
                                    DatePattern.NORM_DATETIME_PATTERN));

                    OaUserEntity user = userMap.get(oaLearnEntryEntity.getOpenid());
                    if (user != null) {
                        learnEntryDetailVO.setSex(user.getSex())
                                .setType(user.getType())
                                .setPoliticsStatus(user.getPoliticsStatus());
                    }

                    String[] split = StringUtils.split(oaLearnEntryEntity.getPath(), ",");

                    List<String> pLearnClass = new ArrayList<>();
                    for (String str : split) {
                        if (!str.equals("0")) {
                            String pClass = map.get(Integer.valueOf(str));
                            if (pClass != null) {
                                pLearnClass.add(pClass);
                            }
                        }
                    }

                    learnEntryDetailVO.setLearnClass(StringUtils.join(pLearnClass, "-"));

                    return learnEntryDetailVO;
                })
                .collect(Collectors.toList());

        List<Map<String, Object>> excelList = new ArrayList<>();
        Map<String, Object> header = new HashMap<>();
        header.put("sheetName", "报名表");
        excelList.add(header);

        for (OaLearnEntryDetailVO oaLearnEntryDetailVO : list) {
            Map<String, Object> line = new HashMap<>();
            line.put("name", oaLearnEntryDetailVO.getName());
            line.put("learnClass", oaLearnEntryDetailVO.getLearnClass());
            line.put("sex", oaLearnEntryDetailVO.getSex() == 1 ? "男" : "女");
            line.put("politicsStatus", oaLearnEntryDetailVO.getPoliticsStatus());
            line.put("type", oaLearnEntryDetailVO.getType());
            line.put("addTime", oaLearnEntryDetailVO.getAddTime());
            excelList.add(line);
        }

        String[] columnNames = {"用户名称", "单位", "性别", "政治面貌", "身份", "报名时间"};
        String[] keys = {"name", "learnClass", "sex", "politicsStatus", "type", "addTime"};

        response.setContentType("application/x-download");
        response.addHeader("Content-Disposition", "attachment;filename=报名表.xlsx;filename*=UTF-8''"
                + URLUtil.encode("报名表.xlsx"));
        try (SXSSFWorkbook xssfWorkbook = ExcelsUtil.ExcelSingleOutputStream(excelList, keys, columnNames)) {
            xssfWorkbook.write(response.getOutputStream());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException("下载异常");
        }
    }

    @Override
    public RateVO orgRate(Date startDate, Date endDate, Integer learnId, Integer pid) {

        List<OaLearnEntity> learns = getOaLearnEntities(startDate, endDate, learnId);
        // 获取所有
        List<OaLearnClassEntity> learnClassEntityList = oaLearnClassService.listByIdAndPid(pid);
        List<OaLearnEntryVO> oaLearnEntryVOS = orgRate(learns, learnClassEntityList);
        List<String> leanNames = learns.stream().map(OaLearnEntity::getName).collect(Collectors.toList());
        RateVO rateVO = new RateVO(oaLearnEntryVOS, leanNames);

        return rateVO;
    }

    public List<OaLearnEntryVO> orgRate(List<OaLearnEntity> learns, List<OaLearnClassEntity> learnClassEntityList) {

        if (learns == null) {
            throw new ServiceException("所选期不存在");
        }
        List<String> pids = learns.stream().map(OaLearnEntity::getPid).collect(Collectors.toList());
        List<OaLeamPeriodsEntity> leamPeriods = (List)oaLeamPeriodsService.listByIds(pids);
        if (leamPeriods == null) {
            throw new ServiceException("所选季不存在");
        }

        // 过滤不存在的选季
        Set<String> pidSet = leamPeriods.stream().map( leamPeriod -> String.valueOf(leamPeriod.getId())).collect(Collectors.toSet());
        List<Integer> learnIds = learns.stream().filter(learn -> pidSet.contains(learn.getPid())).map(OaLearnEntity::getId).distinct().collect(Collectors.toList());

        NumberFormat nt = NumberFormat.getPercentInstance();
        nt.setMinimumFractionDigits(2);

        List<OaLearnEntryCompareInfoVO> list = learnClassEntityList.stream()
                .map(learnClass -> {
                    OaLearnEntryCompareInfoVO learnEntryCompareInfoVO = new OaLearnEntryCompareInfoVO().setId(learnClass.getId());
                    learnEntryCompareInfoVO.setName(learnClass.getName());
                    List<OaLearnNumberDTO> learnNumberDTOS = oaLearnEntryDao.selectLearnNumberByPathGroup(learnIds,
                            learnClass.getPath() + learnClass.getId() + ",");
                    // 总计参与人数
                    Integer number = learnNumberDTOS.stream().map(OaLearnNumberDTO::getNumber).reduce(0, (a, b) -> a + b);
                    Integer total = learnClass.getNum();
                    double rate = (double) 0;
                    List<OaLearnEntryCompareItemVO> itemVOList = new ArrayList<>();
                    for (int i = 0; i < learnIds.size(); i++) {
                        if (total > 0 && number != null) {
                            double r = number * 1.0 / total/learnIds.size();
                            rate = Math.round(r * 10000) / 10000.0;
                        }
                        learnEntryCompareInfoVO.setRate(rate);
                        learnEntryCompareInfoVO.setRatio(nt.format(rate));
                        learnEntryCompareInfoVO.setCount(number == null ? 0 : number);
                    }
                    learnEntryCompareInfoVO.setList(itemVOList);
                    return learnEntryCompareInfoVO;
                }).collect(Collectors.toList());

        List<OaLearnEntryVO> oaLearnEntryVOS = OaLearnEntryVO.convertToOaLearnEntryVO(list);
        Comparator<OaLearnEntryVO> comparator = (o1, o2) ->  Double.valueOf(o1.getRate()).compareTo(o2.getRate());
        List<OaLearnEntryVO> oaLearnEntryVOs = oaLearnEntryVOS.stream().sorted(comparator).collect(Collectors.toList());
        Collections.reverse(oaLearnEntryVOs);
        return oaLearnEntryVOs;
    }


    @Override
    public RateVO schoolRate(Date startDate, Date endDate, Integer type, Integer learnId) {

        List<OaLearnClassEntity> learnClassEntityList = null;
        if( ObjectUtil.isNull(type) || OaLearnClassTypeEnum.isContentSchool(type) == false ){
            learnClassEntityList = oaLearnClassService.listSchool();
        }else{
            learnClassEntityList = oaLearnClassService.listSchool(type);
        }
        List<OaLearnEntity> learns = getOaLearnEntities(startDate, endDate, learnId);
        // 获取所有
        List<OaLearnEntryVO> oaLearnEntryVOS = orgRate(learns, learnClassEntityList);
        RateVO rateVO = new RateVO();
        rateVO.setLists(oaLearnEntryVOS);
        List<String> leanNames = learns.stream().map(OaLearnEntity::getName).collect(Collectors.toList());
        rateVO.setLeanNames(leanNames);

        return rateVO;
    }

    @Override
    public RateVO prefectureRate(Date startDate, Date endDate, Integer learnId) {

        List<OaLearnClassEntity> learnClassEntityList = oaLearnClassService.listPrefecture();
        List<OaLearnEntity> learns = getOaLearnEntities(startDate, endDate, learnId);
        // 获取所有
        List<OaLearnEntryVO> oaLearnEntryVOS = orgRate(learns, learnClassEntityList);
        List<String> leanNames = learns.stream().map(OaLearnEntity::getName).collect(Collectors.toList());
        RateVO rateVO = new RateVO();
        rateVO.setLists(oaLearnEntryVOS);
        rateVO.setLeanNames(leanNames);
        return rateVO;
    }

    @Override
    public void prefectureDownload(Date startDate, Date endDate, Integer learnId) {

        String title = "";
        List<OaLearnClassEntity> learnClassEntityList = oaLearnClassService.listPrefecture();
        List<OaLearnEntity> learns = getOaLearnEntities(startDate, endDate, learnId);
        // 获取所有
        List<OaLearnEntryVO> oaLearnEntryVOS = orgRate(learns, learnClassEntityList);

        if (ObjectUtil.isNull(learnId)) {
            title = DateUtil.format(startDate, DatePattern.NORM_DATE_PATTERN) + "~" + DateUtil.format(endDate, DatePattern.NORM_DATE_PATTERN)+"期汇总";
        } else {
            title = learns.get(0).getName();
        }
        ExcelsUtil.export(oaLearnEntryVOS, OaLearnEntryVO.headerAlias, "数据导出.xlsx", title);
    }

    @Override
    public void drawExcel(OaLearnEntryCompareVO compare) {

        ExcelWriter excel = ExcelUtil.getWriter();
        Workbook workbook = excel.getWorkbook();

        // 定义样式区域
        CellStyle cellStyle = getCellStyle( workbook, IndexedColors.BLACK.index);
        CellStyle downStyle = getCellStyle( workbook, IndexedColors.GREEN.index);
        CellStyle upStyle = getCellStyle( workbook, IndexedColors.RED.index);
        CellStyle textWarp = workbook.createCellStyle();
        textWarp.setWrapText(true);


        Sheet sheet = workbook.getSheetAt(0);
        // 总列 = 比较期 * 2  + 序号 + 期 + 机构列
        int columnCount = compare.getCompare().size() * 2 + 3;
        // 总行数 = 头信息 + 列信息
        int rowCount = compare.getPage().size() + 2;
        for (int i = 0; i < rowCount; i++) {
            Row row = sheet.createRow(i);
            short height = 50*20;
            row.setHeight(height);
            for (int j = 0; j < columnCount; j++) {
                Cell cell = row.createCell(j);
                cell.setCellValue("||||||||||");
            }
        }
        // 绘制头信息
        Row row = sheet.getRow(0);
        Row row1 = sheet.getRow(1);
        // 合并单元格
        CellRangeAddress indexRegion = new CellRangeAddress(0,1,0, 0);
        sheet.addMergedRegion(indexRegion);
        row.getCell(0).setCellValue("序号");

        // 合并单元格
        CellRangeAddress schoolRegion = new CellRangeAddress(0,1,1, 1);
        sheet.addMergedRegion(schoolRegion);
        row.getCell(1).setCellValue("学校");
        // 合并单元格
        row.getCell(2).setCellValue(compare.getChoose());
        row1.getCell(2).setCellValue("参与率");

        int step = 0;
        for (int i = 0; i < compare.getCompare().size(); i++ ) {
            List<String> compareNameList = compare.getCompare();
            int leftIndex = 3 + step;
            int rightIndex = 4 + step;
            CellRangeAddress passTerm = new CellRangeAddress(0,0,leftIndex, rightIndex);
            sheet.addMergedRegion(passTerm);
            row.getCell(leftIndex).setCellValue(compareNameList.get(i));
            row1.getCell( leftIndex ).setCellValue("参与率");
            row1.getCell( rightIndex ).setCellValue("升降");;
            step = step + 2;
        }

        for (int i = 0; i < columnCount; i++) {
            // 列宽度
            sheet.setColumnWidth( i,25*256 );
            row.getCell(i).setCellStyle(cellStyle);
            row1.getCell(i).setCellStyle(cellStyle);
        }

        // 绘制表格信息
        List<OaLearnEntryCompareInfoVO> page = compare.getPage();
        for (int i = 0; i < page.size(); i++) {

            OaLearnEntryCompareInfoVO oaLearnEntryCompareInfoVO = page.get(i);
            Row row2 = sheet.getRow(2 + i);
            if(i == 0){
                row2.getCell(0).setCellValue("");
            }else{
                row2.getCell(0).setCellValue(i);
            }

            row2.getCell(1).setCellValue(oaLearnEntryCompareInfoVO.getName());
            row2.getCell(1).setCellStyle(textWarp);
            row2.getCell(2).setCellValue((NumberUtil.roundStr(oaLearnEntryCompareInfoVO.getRate() * 100, 2) )+"%");

            List<OaLearnEntryCompareItemVO> list = oaLearnEntryCompareInfoVO.getList();
            int step2 = 0;
            for (int j = 0; j < list.size(); j++) {

                OaLearnEntryCompareItemVO oaLearnEntryCompareItemVO = list.get(j);
                row2.getCell(3+step2).setCellValue(oaLearnEntryCompareItemVO.getRatio());
                if(oaLearnEntryCompareItemVO.getRate() == 0){
                    row2.getCell(4+step2).setCellStyle(cellStyle);
                }else if(oaLearnEntryCompareItemVO.getRate() == 1){
                    row2.getCell(4+step2).setCellStyle(upStyle);
                }else {
                    row2.getCell(4+step2).setCellStyle(downStyle);
                }
                row2.getCell(4+step2).setCellValue(oaLearnEntryCompareItemVO.getTranceRate());
                step2+=2;
            }
        }
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setHeader("Content-Disposition","attachment;filename=test.xls");
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
        } catch (IOException e) {
            throw new ServiceException("获取输出流失败！");
        }
        excel.flush(out, true);
        // 关闭writer，释放内存
        excel.close();
        //此处记得关闭输出Servlet流
        IoUtil.close(out);
    }

    public CellStyle getCellStyle( Workbook wb, short fontColor ){

        CellStyle cellStyle = wb.createCellStyle();
        Font font = wb.createFont();
        // 加粗
        font.setBold(false);
        // 字体
        font.setFontName("微软雅黑");
        // 字体高度
        font.setFontHeightInPoints((short) 14);
        // 字体颜色：黑色
        font.setColor(fontColor);
        cellStyle.setFont(font);
        cellStyle.setWrapText(true);
        return cellStyle;
    }

    @Override
    public void schoolDownload(Date startDate, Date endDate, Integer type, Integer learnId) {

        String title = "";
        List<OaLearnClassEntity> learnClassEntityList = null;
        if( ObjectUtil.isNull(type) || OaLearnClassTypeEnum.isContentSchool(type) == false ){
            learnClassEntityList = oaLearnClassService.listSchool();
        }else{
            learnClassEntityList = oaLearnClassService.listSchool(type);
        }
        List<OaLearnEntity> learns = getOaLearnEntities(startDate, endDate, learnId);
        // 获取所有
        List<OaLearnEntryVO> oaLearnEntryVOS = orgRate(learns, learnClassEntityList);

        if (ObjectUtil.isNull(learnId)) {
            title = DateUtil.format(startDate, DatePattern.NORM_DATE_PATTERN) + "~" + DateUtil.format(endDate, DatePattern.NORM_DATE_PATTERN)+"期汇总";
        } else {
            title = learns.get(0).getName();
        }
        ExcelsUtil.export(oaLearnEntryVOS, OaLearnEntryVO.headerAlias, "数据导出.xlsx", title);
    }



    @Override
    public void download(Date startDate, Date endDate, Integer pid, Integer learnId) {

        String title = "";
        List<OaLearnEntity> learns = getOaLearnEntities(startDate, endDate, learnId);
        // 获取所有
        List<OaLearnClassEntity> learnClassEntityList = oaLearnClassService.listByIdAndPid(pid);
        List<OaLearnEntryVO> oaLearnEntryVOS = orgRate(learns, learnClassEntityList);
        if (ObjectUtil.isNull(learnId)) {
            title = DateUtil.format(startDate, DatePattern.NORM_DATE_PATTERN) + "~" + DateUtil.format(endDate, DatePattern.NORM_DATE_PATTERN)+"期汇总";
        } else {
            title = learns.get(0).getName();
        }
        ExcelsUtil.export(oaLearnEntryVOS, OaLearnEntryVO.headerAlias, "数据导出.xlsx", title);
    }


    /**
     * 获取期的信息
     * @param startDate
     * @param endDate
     * @param learnId
     * @return
     */
    private List<OaLearnEntity> getOaLearnEntities(Date startDate, Date endDate, Integer learnId) {

        if(ObjectUtil.isNull(learnId) &&
                ((ObjectUtil.isNull(startDate) || ObjectUtil.isNull(endDate)))){
            throw new ServiceException("请选择期 或 选择期的时间段");
        }
        List<OaLearnEntity> learns = new ArrayList<>();
        if (ObjectUtil.isNull(learnId)) {
            long startSecond = startDate.getTime() / 1000;
            long endSecond = endDate.getTime() / 1000;
            // 1. 查询往期
            List<OaLearnEntity> list = oaLearnService.list(startSecond, endSecond);
            if (CollectionUtil.isEmpty(list)) {
                throw new ServiceException("当前时间段" + DateUtil.format(startDate, DatePattern.NORM_DATE_PATTERN) + "~" + DateUtil.format(endDate, DatePattern.NORM_DATE_PATTERN) + "未查询到期信息！");
            }
            learns.addAll(list);
        } else {
            OaLearnEntity byId = oaLearnService.getById(learnId);
            if (ObjectUtil.isNull(byId)) {
                throw new ServiceException("未查询到期信息！");
            }
            learns.add(byId);
        }
        return learns;
    }









}